/*
*****************************************************************************
*
*      GSM AMR-NB speech codec   R98   Version 7.6.0   December 12, 2001
*                                R99   Version 3.3.0                
*                                REL-4 Version 4.1.0                
*
*****************************************************************************
*
*      File             : coder.c
*      Purpose          : Speech encoder main program.
*
*****************************************************************************
*
*    Usage : coder speech_file  bitstream_file
*
*    Format for speech_file:
*      Speech is read from a binary file of 16 bits data.
*
*    Format for bitstream_file:
*        1 word (2-byte) for the TX frame type
*          (see frame.h for possible values)
*      244 words (2-byte) containing 244 bits.
*          Bit 0 = 0x0000 and Bit 1 = 0x0001
*        1 word (2-byte) for the mode indication
*          (see mode.h for possible values)
*        4 words for future use, currently written as zero
*
*****************************************************************************
*/
 
/*
*****************************************************************************
*                         INCLUDE FILES
*****************************************************************************
*/
#include "typedef.h"
#include "cnst.h"
#include "mode.h"
#include "frame.h"
#include "sp_enc.h"
#include "sp_dec.h"
#include "pre_proc.h"
#include "sid_sync.h"
#include "vadname.h"
#include "e_homing.h"
#include "d_homing.h"

/* frame size in serial bitstream file (frame type + serial stream + flags) */
#define SERIAL_FRAMESIZE (1+MAX_SERIAL_SIZE+5)

/*
********************************************************************************
*                         LOCAL PROGRAM CODE
********************************************************************************
*/
static enum RXFrameType tx_to_rx (enum TXFrameType tx_type)
{
    switch (tx_type) {
      case TX_SPEECH_GOOD:      return RX_SPEECH_GOOD;
      case TX_SPEECH_DEGRADED:  return RX_SPEECH_DEGRADED;
      case TX_SPEECH_BAD:       return RX_SPEECH_BAD;
      case TX_SID_FIRST:        return RX_SID_FIRST;
      case TX_SID_UPDATE:       return RX_SID_UPDATE;
      case TX_SID_BAD:          return RX_SID_BAD;
      case TX_ONSET:            return RX_ONSET;
      case TX_NO_DATA:          return RX_NO_DATA;
      //default:
      //fprintf(stderr, "tx_to_rx: unknown TX frame type %d\n", tx_type);
      //exit(1);
    }
}

/*
*****************************************************************************
*                         LOAD H FILES
*****************************************************************************
*/

unsigned short ModeSequence[] = {
#include "allmodes.h"
};

unsigned short EncoderInput[] = {
#include "encIn_BE.h"

};

unsigned short EncoderOutput[] = {
#include "bitsream_BE.h"
};

unsigned short DecoderInput[] = {
#include "bitsream_BE.h"
};

unsigned short DecoderOutput[] = {
#include "decOut_BE.h"
};


/*
*****************************************************************************
*                             MAIN PROGRAM 
*****************************************************************************
*/

//counter
long counter_init = 0x00707007;
long counter_stop = 0x00000000;
long encoder_counter_result;
long decoder_counter_result;
long encoder_counter[100];
long decoder_counter[100];
long encoder_counter_sum;
long decoder_counter_sum;


Word32 frame, NumOfFrames;
short EncoderError, DecoderError;

int main (void)
{ 
  Word16 new_speech[L_FRAME];         /* Pointer to new speech data        */
  Word16 serial[SERIAL_FRAMESIZE];    /* Output bitstream buffer           */
  Word16 synth[L_FRAME];              /* Synthesis                     */

  Word16 dtx = 1;                     /* enable encoder DTX                */
  
  int i;
  enum Mode mode;
  enum Mode used_mode;
  enum TXFrameType tx_type;
  enum RXFrameType rx_type = (enum RXFrameType)0;

  
  Speech_Encode_FrameState *speech_encoder_state = NULL;
  Speech_Decode_FrameState *speech_decoder_state = NULL;

  int rxframetypeMode = 0;           /* use RX frame type codes       */

  Word16 reset_flag = 0;
  Word16 reset_flag_old = 1;

  sid_syncState *sid_state = NULL;
 
  encoder_counter_sum = 0;
  decoder_counter_sum = 0;
  
  /*-----------------------------------------------------------------------*
   * Initialisation of the coder.                                          *
   *-----------------------------------------------------------------------*/
  if (Speech_Encode_Frame_init(&speech_encoder_state, dtx, "encoder") || sid_sync_init (&sid_state))
  	while(1);
      //exit(-1);

  /*-----------------------------------------------------------------------*
   * Process speech frame by frame                                         *
   *-----------------------------------------------------------------------*/
  EncoderError = 0;
  DecoderError = 0;
  NumOfFrames = (sizeof(EncoderInput)/sizeof(Word16))/L_FRAME;

  for(frame = 0; frame < NumOfFrames; frame++)
  {
     /* read new mode string from file if required */
     mode = ModeSequence[frame];
     
	 /* read new input frame */
	 for (i = 0; i < L_FRAME; i++)
		 new_speech[i] = EncoderInput[frame*L_FRAME + i];
	      
     /* zero flags and parameter bits */
     for (i = 0; i < SERIAL_FRAMESIZE; i++)
         serial[i] = 0;

     /* check for homing frame */
     reset_flag = encoder_homing_frame_test(new_speech);
     
     /* encode speech */
	 start_pref_counter(counter_init);			//init counter
     Speech_Encode_Frame(speech_encoder_state, mode, new_speech, &serial[1], &used_mode); 
	 encoder_counter_result = read_ASM();		//read counter
	 encoder_counter[frame] = encoder_counter_result;
	 encoder_counter_sum += encoder_counter_result;
	 
     /* include frame type and mode information in serial bitstream */
     sid_sync (sid_state, used_mode, &tx_type);

     serial[0] = tx_type;
     if (tx_type != TX_NO_DATA) {
       serial[1+MAX_SERIAL_SIZE] = mode;
     }
     else {
       serial[1+MAX_SERIAL_SIZE] = -1;
     }

	 /* BBB test */
	 for (i = 0; i< SERIAL_FRAMESIZE; i++)
		 if (serial[i] != EncoderOutput[frame*SERIAL_FRAMESIZE + i])
			 EncoderError++;

     /* perform homing if homing frame was detected at encoder input */
     if (reset_flag != 0)
     {
         Speech_Encode_Frame_reset(speech_encoder_state);
         sid_sync_reset(sid_state);
     }
  }
  
  /*-----------------------------------------------------------------------*
   * Close down speech coder                                               *
   *-----------------------------------------------------------------------*/
  //Speech_Encode_Frame_exit(&speech_encoder_state);
  sid_sync_exit (&sid_state);
  





   /*-----------------------------------------------------------------------*
   * Initialization of decoder                                             *
   *-----------------------------------------------------------------------*/
  if (Speech_Decode_Frame_init(&speech_decoder_state, "Decoder"))
  	while(1);
  //    exit(-1);
    
  /*-----------------------------------------------------------------------*
   * process serial bitstream frame by frame                               *
   *-----------------------------------------------------------------------*/

  NumOfFrames = (sizeof(DecoderOutput)/sizeof(Word16))/L_FRAME;

  for(frame = 0; frame < NumOfFrames; frame++)
  {
	 /* read new input frame */
	 for (i = 0; i < SERIAL_FRAMESIZE; i++)
		  serial[i] = DecoderInput[frame*SERIAL_FRAMESIZE + i];


     /* get frame type and mode information from frame */
     if (rxframetypeMode) {
         rx_type = (enum RXFrameType)serial[0];
     } else {
         tx_type = (enum TXFrameType)serial[0];
         rx_type = tx_to_rx (tx_type);
     }
     mode = (enum Mode) serial[1+MAX_SERIAL_SIZE];


     if (rx_type == RX_NO_DATA) {
       mode = speech_decoder_state->prev_mode;
     }
     else {
       speech_decoder_state->prev_mode = mode;
     }

     /* if homed: check if this frame is another homing frame */
     if (reset_flag_old == 1)
     {
         /* only check until end of first subframe */
         reset_flag = decoder_homing_frame_test_first(&serial[1], mode);
     }
     /* produce encoder homing frame if homed & input=decoder homing frame */
     if ((reset_flag != 0) && (reset_flag_old != 0))
     {
         for (i = 0; i < L_FRAME; i++)
         {
             synth[i] = EHF_MASK;
         }
     }
     else
     {     
         /* decode frame */		 
		 start_pref_counter(counter_init);			//init counter
         Speech_Decode_Frame(speech_decoder_state, mode, &serial[1], rx_type, synth);		 
		 decoder_counter_result = read_ASM();		//read counter
		 decoder_counter[frame] = decoder_counter_result;
		 decoder_counter_sum += decoder_counter_result;
     }

	 /* BBB test */
	 for (i = 0; i < L_FRAME; i++)
		 if (synth[i] != (short)DecoderOutput[frame*L_FRAME + i])
			 DecoderError++;
     
     /* if not homed: check whether current frame is a homing frame */
     if (reset_flag_old == 0)
     {
         /* check whole frame */
         reset_flag = decoder_homing_frame_test(&serial[1], mode);
     }
     /* reset decoder if current frame is a homing frame */
     if (reset_flag != 0)
     {
         Speech_Decode_Frame_reset(speech_decoder_state);
     }
     reset_flag_old = reset_flag;

  }
  
  /*-----------------------------------------------------------------------*
   * Close down speech decoder                                             *
   *-----------------------------------------------------------------------*/
  //Speech_Decode_Frame_exit(&speech_decoder_state);
  return 0;

}

